// 常用的内置函数源码实现
// 不使用任何库（除了NULL之外）
#include <stdio.h>

/// @brief 实现atoi函数，字符串转为整数
/// @param s 原字符串
/// @return 转换的数字
int myAtoi(char *s)
{
	if (s == NULL)
	{
		return 0;
	}
	int n = 0, sign = 1;
	if (*s == '-')
	{
		sign = -1;
	}
	// 跳过符号
	while (*s == '-' || *s == '+')
	{
		s++;
	}
	while (*s != '\0')
	{
		n = n * 10 + (*s - '0');
		s++;
	}
	return sign * n;
}

/// @brief 实现itoa函数，整数转字符串
/// @param n 待转换的整数
/// @param s 存放结果的字符串
void myItoa(int n, char *s)
{
	if (s == NULL)
	{
		return;
	}
	if (n == 0)
	{
		*s = '0';
		*(s + 1) = '\0';
		return;
	}
	// 是否为负数
	if (n < 0)
	{
		n = -n;
		*s = '-';
		s++;
	}
	// 记录字符串起始地址以便于后续反转
	char *origin = s;
	// 转换
	while (n != 0)
	{
		*s = '0' + n % 10;
		s++;
		n /= 10;
	}
	*s = '\0';
	// 反转
	s--;
	char temp;
	while (origin < s)
	{
		temp = *origin;
		*origin = *s;
		*s = temp;
		origin++;
		s--;
	}
}

/// @brief 实现strcat函数，将两个字符串连接起来
/// @param strDes 前字符串
/// @param strSrc 后字符串
/// @return strDes的首地址
char *myStrcat(char *strDes, const char *strSrc)
{
	if (strDes == NULL || strSrc == NULL)
	{
		return NULL;
	}
	char *address = strDes;
	// 先索引到strDes的末尾
	while (*strDes != '\0')
	{
		strDes++;
	}
	// 然后把strSrc的内容逐个追加
	while (*strSrc != '\0')
	{
		*strDes++ = *strSrc++;
	}
	*strDes = '\0';
	return address;
}

/// @brief 实现strncat函数，把strSrc的前n个字符追加到strDes末尾
/// @param strDes 前字符串
/// @param strSrc 后字符串
/// @param n 追加个数
/// @return strDes首地址
char *myStrncat(char *strDes, const char *strSrc, int n)
{
	if (strDes == NULL || strSrc == NULL)
	{
		return NULL;
	}
	char *address = strDes;
	// 先索引到strDes末尾
	while (*strDes != '\0')
	{
		strDes++;
	}
	// 追加
	while (n-- && *strSrc != '\0')
	{
		*strDes++ = *strSrc++;
	}
	*strDes = '\0';
	return address;
}

/// @brief 实现strcpy函数，将原字符串内容复制到目标字符串
/// @param strDes 目标字符串
/// @param strSrc 原字符串
/// @return 目标字符串首地址
char *myStrcpy(char *strDes, const char *strSrc)
{
	if (strDes == NULL || strSrc == NULL)
	{
		return NULL;
	}
	char *address = strDes;
	while (*strSrc != '\0')
	{
		*strDes++ = *strSrc++;
	}
	*strDes = '\0';
	return address;
}

/// @brief 实现strncpy函数，将原字符串的前n个字符复制到目标字符串中
/// @param strDes 目标字符串
/// @param strSrc 原字符串
/// @param n 字符数
/// @return 目标字符串首地址
char *myStrncpy(char *strDes, const char *strSrc, int n)
{
	if (strDes == NULL || strSrc == NULL)
	{
		return NULL;
	}
	char *address = strDes;
	while (n-- && *strSrc != '\0')
	{
		*strDes++ = *strSrc++;
	}
	*strDes = '\0';
	return address;
}

/// @brief 实现strcmp函数，比较两个字符串
/// @param s 第一个字符串
/// @param t 第二个字符串
/// @return 两字符串完全相同则返回0，否则返回第一个不相等的字符的差值
int myStrcmp(const char *s, const char *t)
{
	// 逐个字符比较，字符相等且未结束时比较下一个
	while (*s != '\0' && *t != '\0' && *s == *t)
	{
		s++;
		t++;
	}
	// 若从头到尾相等，此时s和t应当都指向字符串末尾'\0'，因此返回0
	// 不相等退出则会返回两个不等字符的差值
	return *s - *t;
}

/// @brief 实现strncmp函数，比较s和t两个字符串的前n个字符
/// @param s 第一个字符串
/// @param t 第二个字符串
/// @param n 比较字符数
/// @return 两字符串前n个完全相同则返回0，否则返回第一个不相等的字符的差值
int myStrncmp(const char *s, const char *t, int n)
{
	// 逐个比较
	// 之所以是--n不是n--，是因为如果是n--的话，循环结束时s和t已经指向了第n + 1个字符了，因此往前一个
	while (*s != '\0' && *t != '\0' && *s == *t && --n)
	{
		s++;
		t++;
	}
	return *s - *t;
}

/// @brief 实现strlen函数，统计字符串长度
/// @param s 字符串
/// @return 字符串长度，不包括最后的'\0'
int myStrlen(char *s)
{
	if (s == NULL)
	{
		return 0;
	}
	int n = 0;
	while (*s != '\0')
	{
		s++;
		n++;
	}
	return n;
}

int main()
{
	char s[100] = "abcdssseg";
	char t[100] = "abcdef";
	printf("%d\n", myStrlen(s));
	return 0;
}